from django.shortcuts import render, redirect
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.routers import DefaultRouter
from users.models import User
import re
import redis
import qrcode
import zxing
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.conf import settings
import os
from io import BytesIO
from .models import PhoneCollection
from users.serializers import UserSer

from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import CreateModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.generics import GenericAPIView
from rest_framework.generics import ListAPIView # 查看所有
from rest_framework.generics import CreateAPIView # 插入一个
from rest_framework.generics import UpdateAPIView # 更新一个
from rest_framework.generics import DestroyAPIView # 删除一个
from rest_framework.generics import RetrieveAPIView # 查看一个


# Create your views here.

# 注册视图
class Register(APIView):
    @csrf_exempt
    def post(self, request):

        # 1. get data from frontend
        username = request.data.get("username")
        password = request.data.get("password")
        confirm_password = request.data.get("confirmPass")
        phone = request.data.get("phone")
        vcode = request.data.get("vcode")
        uuid_ = request.data.get("imageCodeID")

        # 2.calibrate data
        if not all([username, password, confirm_password, phone, vcode]):
            return Response({"code":204, "msg":"信息不完整"})

        # 用户名以字母开头，包含字母数据下划线，长度6-12
        if not re.findall(r"^[a-zA-Z]\w{5,11}$", username):
            return Response({"code":204, "msg":"用户名以字母开头，包含字母数据下划线，长度6-12"})

        # 用户名不能重复
        user_queryset = User.objects.filter(username=username)

        if user_queryset:
            return Response({"code":204, "msg":"用户名已注册"})

        # 验证密码
        if password != confirm_password:
            return Response({"code":204, "msg":"两次密码不一致"})

        # 验证手机号
        if not re.findall(r"^1\d{10}$", phone):
            return Response({"code":204, "msg":"手机号不符合要求"})

        # 验证图形验证码
        key = "imageCode:%s"%uuid_
        redis_conn = redis.Redis(host='localhost', port=6379, db=0, password='laufing')
        store_code = redis_conn.get(key)
        if not store_code:
            return Response({"code":204, "msg":"验证码已过期"})

        # 对比验证码
        if store_code.decode().lower() != vcode.lower():
            return Response({"code":204, "msg":"验证码输入错误"})

        # 3. 创建用户
        User.objects.create_user(username=username, password=password, mobile=phone)

        return Response({"code":200, "msg":"注册成功"})

# 生成二维码 视图类
class BarCode(APIView):
    # 生成二维码
    def get(self, request):

        # 1. 跳转的url
        # reader = zxing.BarCodeReader()
        # bar_code = reader.decode(os.path.join(settings.BASE_DIR, 'code.jpg'))  # 解析支付宝红包的地址
        # url = bar_code.parsed
        # print("当前地址:", url)
        url = "http://192.168.0.104:8000/v1/users/phone"

        # 2. 生成二维码
        qr = qrcode.QRCode(
            version=3,
            error_correction=qrcode.constants.ERROR_CORRECT_H,
            box_size=10,
            border=3
        )
        qr.add_data(data=url)

        img = qr.make_image(fill_color="black", back_color="white")
        bar_code_io = BytesIO()
        img.save(bar_code_io, format="png")
        img.save("test.png")


        return HttpResponse(bar_code_io.getvalue(), content_type='image/png')


# 收集手机号视图
class CollectPhone(APIView):
    def get(self, request):
        print("第一次的GET请求头：", request.headers)
        return render(request, "phone.html", {"code":200})

    def post(self, request):
        print("第二次的POST请求头：", request.headers)
        # 1.获取用户的手机号
        phone = request.data.get("phone")
        print("获取到手机号：", phone)

        # 2. 验证手机号
        if not re.findall(r"^1[3-9]\d{9}$", phone):
            return render(request, "phone.html", {"code":204, "msg":"非法手机号", "phone":phone})

        # 3. 存储手机号
        phone_queryset = PhoneCollection.objects.filter(mobile=phone)
        if not phone_queryset:
            PhoneCollection.objects.create(mobile=phone)

        # 4. 解析支付宝红包地址
        reader = zxing.BarCodeReader()
        bar_code = reader.decode(os.path.join(settings.BASE_DIR, 'code.jpg'))  # 解析支付宝红包的地址
        url = bar_code.parsed
        print("当前地址:", url)
        return redirect(url)   #失效    支付宝有 数据校验，

        # return render(request, "skip.html", {"skip_url":url})


# class UserAPIView(ListAPIView, CreateAPIView):
#     queryset = User.objects.all()
#     serializer_class = UserSer
#
# class UserDetailAPIView(RetrieveAPIView, UpdateAPIView, DestroyAPIView):
#     queryset = User.objects.all()
#     serializer_class = UserSer
#
#
# from rest_framework.viewsets import ModelViewSet
# class UserViewSet(ModelViewSet):
#     queryset = User.objects.all()
#     serializer_class = UserSer
#
# from rest_framework.generics import GenericAPIView
# from rest_framework.mixins import ListModelMixin, CreateModelMixin
# from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
#
# class UserView1(GenericAPIView, ListModelMixin, CreateModelMixin):
#     queryset = User.objects.all()
#     serializer_class = UserSer
#
#     def get(self, request):
#         return self.list(request)
#
#     def post(self, request):
#         return self.create(request)
#
# class UserView2(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
#     queryset = User.objects.all()
#     serializer_class = UserSer
#
#     def get(self, request, pk):
#         return self.retrieve(request, pk)
#
#     def put(self, request, pk):
#         return self.update(request, pk)
#
#     def delete(self, request, pk):
#         return self.destroy(request, pk)


from rest_framework.viewsets import ViewSetMixin
from rest_framework.decorators import action




class UserViewSetMixin(ViewSetMixin, APIView):


    def my_func(self, request):
        print("自定义的action")

        return Response({"code": 200, "msg": "自定义的action"})


# 用户的认证
from django.contrib.auth.hashers import check_password
import jwt
from django.conf import settings
from datetime import timedelta
from datetime import datetime
from rest_framework.authentication import BaseAuthentication
from jwt.exceptions import ExpiredSignature, DecodeError
from rest_framework.exceptions import AuthenticationFailed
import time


class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.headers.get("Authorization")
        print("认证token:", token)
        if token.startswith("Bearer"):
            token = token.split(" ")[-1]
        try:
            payload = jwt.decode(token, key=settings.SECRET_KEY, algorithms=['HS256'])
            print("解码出payload:", payload)
        except ExpiredSignature:
            raise AuthenticationFailed("token已过期")

        except DecodeError:
            raise AuthenticationFailed("非法的token")

        user = User.objects.filter(id=payload.get("uid")).first()
        return user, token


class LoginAPIView(APIView):

    def post(self, request):
        print("请求体数据:", request.data, type(request.data))
        username = request.data.get("username")
        password = request.data.get("password")

        # 查询用户对象
        user = User.objects.filter(username=username).first()
        # print("user:", user)
        if user:
            # validate = check_password(password, user.password)
            validate = password == user.password
            if validate:
                payload = {
                    "uid": user.id,
                    'uname': user.username
                }
                expire = timedelta(seconds=20)
                token = self.generate_token(payload, expire)

                res = Response({"code": 200, "msg": "登录成功"})

                # 设置响应头
                res['token'] = token
                res['author'] = 'laufing'

                return res

        return Response({"code": 204, "msg": '用户名或密码错误'})

    @staticmethod
    def generate_token(payload, expire, secret=None):
        _payload = {
            "exp": datetime.utcnow() + expire  # 当前时间加一个时间差值
        }
        # 将用户信息字典更新到自己内部
        _payload.update(payload)

        if secret:
            ...
        else:
            secret = settings.SECRET_KEY

        return jwt.encode(payload=_payload, key=secret, algorithm="HS256")

from rest_framework.decorators import action
from rest_framework.viewsets import ViewSetMixin
from rest_framework.permissions import IsAuthenticated

from rest_framework.permissions import BasePermission
from rest_framework.throttling import BaseThrottle
from rest_framework.permissions import SAFE_METHODS
from rest_framework.generics import ListAPIView
from rest_framework.status import HTTP_201_CREATED


class MyPermission(BasePermission):
    def has_object_permission(self, request, view, obj):

        print("xxxxx permission:", request, view, obj)

        return obj.user == request.user


class CheckUserAPIView(ViewSetMixin, APIView):
    authentication_classes = [MyAuthentication]
    permission_classes = [IsAuthenticated, MyPermission]
    throttle_classes = []
    queryset = User.objects.all()
    serializer_class = UserSer

    @action(methods=["GET"], detail=False)  # detail 是否允许传入pk
    def myget(self, request):
        print(request.user)
        print(request.auth)
        print(request.authenticators)

        if request.user:

            return Response({"code": 200, "msg": "验证通过"})

        else:
            return Response({"code": 204, "msg": "验证不通过"})



from django.conf import settings
import random
# from users.utils import send_message
from users.tasks import send_message

class SmsCodeView(APIView):

    def post(self, request):

        # 1.接收前端数据
        mobile = request.data.get("mobile")
        uuid_ = request.data.get("uuid")

        # 2. 生成随机验证码
        sms_code = random.randint(1000, 99999)
        expire = 10

        # 3. 给容联云发请求    提交异步任务到celery 队列
        result = send_message.delay(sms_code, mobile, expire)

        # 4. 判断短信是否发送成功
        # if result:
        #     # 成功发送， 存储sms_code----> redis
        #     sms_key = "sms_%s"%uuid_
        #     redis_cli = redis.Redis(host="localhost", port=6379, password="laufing", db=3)
        #     redis_cli.set(sms_key, sms_code)
        #
        #     return Response({"code": 200, "msg": "短信发送成功"})
        #
        # else:
        #     return Response({"code": 400, "msg": "短信发送失败"})

        # 存储短信验证码
        redis_cli = redis.Redis(host="localhost", port=6379, password="laufing", db=3)
        sms_key = "sms_%s"%uuid_
        redis_cli.set(sms_key, sms_code)

        return Response({"code": 200, "msg": "短信已发送，请注意查收"})


from datetime import datetime
from django.contrib.auth.hashers import check_password
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler

# 登录的视图
class LoginCountView(APIView):
    def post(self, request):
        # 1. 接收前端数据
        mobile = request.data.get('mobile')
        sms_code = request.data.get("code")
        username = request.data.get('username')
        password = request.data.get('password')
        uuid_ = request.data.get("uuid")

        # 2. 判断用户是否第一次登录
        user = User.objects.filter(username=username).first()
        redis_cli = redis.Redis(host="localhost", port=6379, password="laufing", db=3)
        sms_key = "sms_%s"%uuid_
        # 是第一次登录
        if not user:
            stored_sms_code = redis_cli.get(sms_key)
            if stored_sms_code:
                if stored_sms_code.decode() == sms_code:
                    # 用户输入的验证码 认证通过
                    User.objects.create_user(username=username, password=password, mobile=mobile, last_login=datetime.now())

                    return Response({"code": "201", "msg": "注册成功，需申请管理员权限"})

            return Response({"code":"204", "msg": "验证码过期或者错误"})

        # 不是第一次登录
        else:
            # 优先使用用户名&密码的方式来登录
            if check_password(password, user.password):
                # 认证用户通过， 检查是否有权限
                if user.is_active and user.is_staff:
                    # 有权限登录站点, 登录成功
                    token = self.gen_token(user)
                    # 预留的bug
                    user.last_login = datetime.now()
                    user.save()
                    return Response({
                        "code": "200",
                        "msg": "登录成功， 进入首页",
                        "token": token,
                        "user": user.username
                    })

                # 认证通过， 但是还没有管理员权限
                return Response({
                    "code": "206",
                    "msg": "没有管理员权限"
                })
            else:
                # 密码校验错误， 使用短信验证码 来验证码当前用户，并重置当前密码
                stored_sms_code = redis_cli.get(sms_key)
                if stored_sms_code:
                    if stored_sms_code.decode() == sms_code:
                        # 用户输入的验证码 认证通过, 则重置密码
                        user.set_password(password)
                        user.save()

                        return Response({"code": "207", "msg": "密码已重置"})

                return Response({"code": "204", "msg": "验证码过期或者错误"})

    @staticmethod
    def gen_token(user):
        """
        :param user:  当前登录的用户对象
        :return:  jwt token
        """
        # 更加用户对象， 生成payload数据
        payload = jwt_payload_handler(user)
        print("生成的payload 数据：", payload)

        # 编码， 生成token
        token = jwt_encode_handler(payload)

        return token


# 统计用户总数
class UserCountView(APIView):
    def get(self, requset):
        # 当前用户总数
        num = User.objects.all().count()
        return Response({
            "code": "200",
            "msg": "获取用户总数成功",
            "total_count": num
        })

# 统计日增用户总数
import time

class DailyAddUserView(APIView):

    def get(self, request):
        date = time.strftime("%Y-%m-%d")
        num = User.objects.filter(date_joined__contains=date).count()

        return Response({
            "code": "200",
            "msg": "日增用户总数",
            "total_count": num
        })

# 统计日活跃用户总数
class DailyActiveUserView(APIView):
    def get(self, request):
        date = time.strftime("%Y-%m-%d")
        num = User.objects.filter(last_login__contains=date).count()
        return Response({
            "code": "200",
            "msg": "日活跃用户总数",
            "total_count": num
        })


<<<<<<< HEAD
# 用户信息的视图集
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination


# 定义分页类
class MyPagination(PageNumberPagination):
    # 默认每页显示的条数
    page_size = 5
    # 每页最大显示 的条数
    max_page_size = 10

    # 根据查询字符串的关键字参数   http://localhost:8000/users/?page=2&pagesize=5
    # 页码
    page_query_param = "page"

    # 每页展示多少条数据
    page_size_query_param = "pagesize"


# 用户信息视图集
class UserInfoViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSer

    pagination_class = MyPagination

    def create(self, request, *args, **kwargs):
        print("新增用户的信息:", request.data)

        # 实例序列化器的对象
        ser = self.get_serializer(data=request.data)

        # 验证用户信息是否满足要求
        if ser.is_valid():

            # 保存用户数据
            ser.save()

            return Response({"code": "200", "msg": "添加用户信息成功", "user": ser.data})

        else:
            return Response({"code": "400", "msg": "用户信息不符合要求" })


#



=======
# 获取用户信息的视图集
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination
>>>>>>> f03f6fc2a5e389c57682ccb2441daf9bc7b6dbf9


class MyPagination(PageNumberPagination):
    page_size = 5
    max_page_size = 6
    page_query_param = "page"
    page_size_query_param = "pagesize"




class UserInfoViewSet(ModelViewSet): # ModelViewSet继承了五个视图子类和GenericAPIView
    queryset = User.objects.all()
    serializer_class = UserSer
    pagination_class = MyPagination

    # 重写create方法，添加用户对象
    def create(self, request, *args, **kwargs):
        print("添加一个用户对象：", request.data)

        # 数据校验
        ser = self.get_serializer(data=request.data)

        # 验证数据是否有效， 使用序列化器中的验证规则
        if ser.is_valid():
            # 保存用户对象
            ser.save()

            # 返回响应
            return Response({"code": "200", "msg": "添加用户成功", "user_info": ser.data})
        else:
            return Response({"code": "400", "msg": "用户数据不符合要求"})






















